package assign3;

/**
 * <p>Title: Ellipse Class</p>
 * Description: CS 235 Assignment 3 
 * 	    Contains the Ellipse Objects 
 * @author Jared Potter, Tim Drallmeier, Kyle Kolstad, and Patrick Altendorfer
 * @date   December 1, 2011
 */

import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;

class Ellipse implements Serializable{
	
	private static final long serialVersionUID = 1L;
	
	int ellipseNum;
	int area, minorAxis, majorAxis, perimeter;
	
	/**
	 * Ellipse Constructor. takes in parameters and sets the vairiables to those parameters
	 * 
	 * @require majAxisIn > 0
	 * 			minAxisIn > 0
	 * 			perIn > 0
	 * 			areaIn > 0
	 * 			ellipseNumIn > 0
	 * 
	 * @ensure this.majorAxis = majAxisIn
	 * 		   this.minorAxis = minAxisIn
	 * 		   this.perimeter = perIn
	 * 		   this.area = areaIn
	 * 		   this.ellipseNum = ellipseNumIn
	 */
	public Ellipse(int majAxisIn, int minAxisIn, int perIn, int areaIn, int ellipseNumIn){
		assert(majAxisIn > 0);
		assert(minAxisIn > 0);
		assert(perIn > 0);
		assert(areaIn > 0);
		assert(ellipseNumIn > 0);
		
		majorAxis =  majAxisIn;
		minorAxis = minAxisIn;
		perimeter = perIn;
		area =	areaIn;
		ellipseNum = ellipseNumIn;
	}
	
	/**
	 * To String for the Ellipse Class
	 * 
	 * @ensure returns string
	 */
	public String toString(){
		return "Ellipse " + ellipseNum + ":          " + majorAxis + "          " + minorAxis + "          " + 
	perimeter + "          " + area;
	}
	
	/**
	 *Returns the MajorAxis for an object
	 * 
	 * @require majorAxis > 0
	 * 
	 * @ensure this.majoraxis = majoraxis
	 */
	public int getMajAx(){
		assert(majorAxis > 0);
		return majorAxis;
	}
	
	/**
	 * Returns the MinorAxis for an object
	 * 
	 * @require minor axis > 0
	 * 
	 * @ensure this.minoraxis = minoraxis
	 */
	public int getMinAx(){
		assert(minorAxis > 0);
		return minorAxis;
	}
	
	/**
	 * Returns Perimeter of an object
	 * 
	 * @require perimeter > 0
	 * 
	 * @ensure this.perimeter = perimeter
	 */
	public int getPerimeter(){
		assert(perimeter > 0);
		return perimeter;
	}
	
	/**
	 * Returns Area on object
	 * 
	 * @require area > 0
	 * 
	 * @ensure this.area = area
	 */
	public int getArea(){
		assert(area > 0);
		return area;
	}
}

/**
 * <p>Title: EllipseListGui Class</p>
 * Description: CS 235 Assignment 3 
 * 	    Contains the setup and creation of the GUI 
 * @author Jared Potter, Tim Drallmeier, Kyle Kolstad, and Patrick Altendorfer 
 * @date   December 1, 2011
 */
public class EllipseListGUI extends JFrame implements ActionListener, Serializable{

	private static final long serialVersionUID = 1L;
	
	String sortAreaString = "Area";
	String sortMinAxisString = "Minor Axis";
	String sortMajAxisString = "Major Axis";
	String sortPariString = "Perimeter";
	
	//GUI button and menu names
	private JList listview;
	private JScrollPane scroll;
	private JButton sortArea, sortMinAxis, sortMajAxis, sortPari;
	private JMenuBar menuBar;
	private JMenu menu;
	private JMenuItem openMenu, saveMenu, newMenu;
	
	private final JFileChooser fc = new JFileChooser();
	
	DefaultListModel listmodel;
	ArrayList<Ellipse> newList, newListIn;

	//locations of scrolls bars, frames, and buttons
	private final int frameX = 100, frameY = 100, frameW = 450,  frameH = 335;
	private final int scrollX = 30, scrollY = 30, scrollW = 255, scrollH = 200;
	private final int buttonX = 300, buttonY = 50, buttonW = 95, buttonH = 30;
	
	/**
	 * Sets up the GUI and ArrayList and ListModel
	 * 
	 * @require title.length() > 0;
	 * 
	 * @ensure GUI is created with drop down menus and buttons
	 */
	public EllipseListGUI(String title) {
		assert(title.length() > 0);
		
		setBounds(frameX, frameY, frameW, frameH);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		setLayout( null );
		
		
		listmodel = new DefaultListModel();
		newList = new ArrayList<Ellipse>();
		
		//sets up a default of 22 ellipses with random numbers between 1 and 30 
		for(int i = 0; i < 22; i++){
			double	rndmNum1  = Math.random()*30 + 1;
			double	rndmNum2  = Math.random()*30 + 1;
			double	rndmNum3  = Math.random()*30 + 1;
			double	rndmNum4  = Math.random()*30 + 1;
			
			Ellipse ellipse = new Ellipse((int)rndmNum1, (int)rndmNum2, (int)rndmNum3, (int)rndmNum4, (i + 1));
			listmodel.addElement(ellipse);
			
			newList.add(ellipse);
		}
		
		//add listmodel and scroll bars to window
		listview = new JList( listmodel );
		listview.setVisible(true);		
		scroll = new JScrollPane( listview );
		scroll.setBounds(scrollX, scrollY, scrollW, scrollH);
		add( scroll );
		
		//creates buttons
		sortMajAxis = new JButton(sortMajAxisString);
		sortMinAxis = new JButton(sortMinAxisString);
		sortPari = new JButton(sortPariString);
		sortArea = new JButton(sortAreaString);
		
		//adds actionlisteners
		sortMajAxis.addActionListener(this);
		sortMinAxis.addActionListener(this);
		sortPari.addActionListener(this);
		sortArea.addActionListener(this);
		
		//set buttons to be on right side of window
		sortMajAxis.setBounds(buttonX, buttonY, buttonW, buttonH);
		sortMinAxis.setBounds(buttonX, buttonY + buttonH + 10, buttonW, buttonH);
		sortPari.setBounds(buttonX, buttonY + buttonH*2 + 20, buttonW, buttonH);
		sortArea.setBounds(buttonX, buttonY + buttonH*3 + 30, buttonW, buttonH);
		
		//adds buttons
		add(sortArea);
		add(sortMinAxis);
		add(sortMajAxis);
		add(sortPari);
		
		//drop down menus
        menuBar = new JMenuBar();
        setJMenuBar(menuBar);
        
        menu = new JMenu("File");
        menuBar.add(menu);
        
		newMenu = new JMenuItem("New");
		newMenu.addActionListener( this );
		menu.add(newMenu);
		
		openMenu = new JMenuItem("Open");
		openMenu.addActionListener( this );
		menu.add(openMenu);
		
		saveMenu = new JMenuItem("Save");
		saveMenu.addActionListener( this );
		menu.add(saveMenu);
		
		//labels
		Label majAxLabel = new Label("MajAx");
		majAxLabel.setBounds(100, 9, 35, 30);
		add(majAxLabel);
		
		Label minAxLabel = new Label("MinAx");
		minAxLabel.setBounds(140, 9, 35, 30);
		add(minAxLabel);
		
		Label pariLabel = new Label("Peri");
		pariLabel.setBounds(185, 9, 30, 30);
		add(pariLabel);
		
		Label areaLabel = new Label("Area");
		areaLabel.setBounds(230, 9, 30, 30);
		add(areaLabel);
		setVisible( true );

	}		

	/**
	 * Interacts with the menus. Uses actionevents to perform specific tasks upon selection
	 * 
	 * @require arg0 != null
	 * 
	 * @ensure new menu clears listmodel
	 * 	 	   open menu opens a saved ellipse list
	 * 		   save menu saves an ellipse list
	 * 		   sortArea sorts ellipses by area
	 * 		   sortPerimeter sorts ellipses by perimeter
	 * 		   sortMajAx sorts ellipses by major axis
	 * 		   sortMinAx sorts ellipses by minor axis
	 */
	@SuppressWarnings("unchecked")
	public void actionPerformed(ActionEvent arg0) {
		assert(arg0 != null);
		
		Object source = arg0.getSource();
		
		if (source.equals(newMenu)){
			
			listmodel.removeAllElements();
			newList.clear();
		}
		
		if (source.equals(openMenu)){
			int result = fc.showOpenDialog(this);
			if(result == JFileChooser.APPROVE_OPTION){
				File file = fc.getSelectedFile();
				
				try{
					//opens stream
					ObjectInputStream oi = new ObjectInputStream(new FileInputStream(file));
					
					//reads in the saved object as an arrayList
					newList = (ArrayList<Ellipse>) oi.readObject();
					
					listmodel.removeAllElements();
					
					//adds objects from newList to the empty ListModel
					for(Ellipse s : newList)
						listmodel.addElement(s);
	
				}catch (FileNotFoundException e) {
					e.printStackTrace();
				}catch (IOException e) {
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
			
		}
		
		if (source.equals(saveMenu)){
			int result = fc.showSaveDialog(this);
		
			if(result == JFileChooser.APPROVE_OPTION){
				File file = fc.getSelectedFile();
				
				try{
					//opens stream
					ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream( file ));
					
					//saves newList to a file
					os.writeObject(newList);
									
				}catch (FileNotFoundException e) {
					e.printStackTrace();
				}catch (IOException e) {
					e.printStackTrace();
				}
			}	
		}
		
		if (source.equals(sortArea)){
		
			//adds whats in the list model to the vector
			newList = new ArrayList<Ellipse>();
			for(int i = 0; i < listmodel.size(); i++)
				newList.add((Ellipse) listmodel.elementAt(i));
		
			Collections.sort(newList, new compareArea());
		
			listmodel.removeAllElements();
		
			//adds the sorted items back into the listmodel
			for(Ellipse s : newList)
				listmodel.addElement(s);
		}
		
		if (source.equals(sortMinAxis)){
			
			//adds whats in the list model to the vector
			newList = new ArrayList<Ellipse>();
			for(int i = 0; i < listmodel.size(); i++)
				newList.add((Ellipse) listmodel.elementAt(i));
		
			Collections.sort(newList, new compareMinAx());
		
			listmodel.removeAllElements();
		
			//adds the sorted items back into the listmodel
			for(Ellipse s : newList)
				listmodel.addElement(s);
		}
		
		if (source.equals(sortMajAxis)){
			
			//adds whats in the list model to the vector
			newList = new ArrayList<Ellipse>();
			for(int i = 0; i < listmodel.size(); i++)
				newList.add((Ellipse) listmodel.elementAt(i));
		
			Collections.sort(newList, new compareMajAx());
		
			listmodel.removeAllElements();
		
			//adds the sorted items back into the listmodel
			for(Ellipse s : newList)
				listmodel.addElement(s);
		}
		
		if (source.equals(sortPari)){
			
			//adds whats in the list model to the vector
			newList = new ArrayList<Ellipse>();
			for(int i = 0; i < listmodel.size(); i++)
				newList.add((Ellipse) listmodel.elementAt(i));
		
			Collections.sort(newList, new comparePeri());
		
			listmodel.removeAllElements();
		
			//adds the sorted items back into the listmodel
			for(Ellipse s : newList)
				listmodel.addElement(s);
		}
	
	}
	

	/**
	 * Main Method. runs the GUI
	 * 
	 * @require args != null
	 * 
	 * @ensure
	 * 
	 */
	public static void main(String[] args) {
		assert(args != null);
		
		new EllipseListGUI("Ellipse List");
	}

	/**
	 * <p>Title: compareArea Class</p>
	 * Description: CS 235 Assignment 3 
	 * 	    Contains the method to allow for sorting by area 
	 * @author Jared Potter, Tim Drallmeier, Kyle Kolstad, and Patrick Altendorfer 
	 * @date   December 1, 2011
	 */
public class compareArea implements Comparator<Ellipse>{

	/**
	 * Compares two Ellipse objects so they can be used to sort by area
	 * 
	 * @require o1.getArea() > 0
	 * 			o2.getArea() > 0
	 * 
	 * @ensure o1.getArea() - o2.getArea() = any valid number
	 */
	
	public int compare(Ellipse o1, Ellipse o2) {
		
		assert(o1.getArea() > 0);
		assert(o2.getArea() > 0);
		
		return o1.getArea() - o2.getArea();
	}
	
}

/**
 * <p>Title: comparePeri Class</p>
 * Description: CS 235 Assignment 3 
 * 	    Contains the methods to sort by perimeter 
 * @author Jared Potter, Tim Drallmeier, Kyle Kolstad, and Patrick Altendorfer 
 * @date   December 1, 2011
 */
public class comparePeri implements Comparator<Ellipse>{
	
	/**
	 * Compares two Ellipse objects so they can be used to sort by perimeter
	 * 
	 * @require o1.getPerimeter() > 0
	 * 			o2.getPerimeter() > 0
	 * 
	 * @ensure o1.getPerimeter() - o2.getPerimeter()  = any valid number
	 */
	
	public int compare(Ellipse o1, Ellipse o2) {
		
		assert(o1.getPerimeter() > 0);
		assert(o2.getPerimeter() > 0);
		
		return o1.getPerimeter() - o2.getPerimeter();
	}
	
}

/**
 * <p>Title: compareMajAx Class</p>
 * Description: CS 235 Assignment 3 
 * 	    Contains the methods to sort by major axis 
 * @author Jared Potter, Tim Drallmeier, Kyle Kolstad, and Patrick Altendorfer 
 * @date   December 1, 2011
 */
public class compareMajAx implements Comparator<Ellipse>{
	
	/**
	 * Compares two Ellipse objects so they can be used to sort by major axis
	 * 
	 * @require o1.getMajAxr() > 0
	 * 			o2.getMajAx() > 0
	 * 
	 * @ensure o1.getMajAx() - o2.getMajAx()  = any valid number
	 */
	
	public int compare(Ellipse o1, Ellipse o2) {
		
		assert(o1.getMajAx() > 0);
		assert(o2.getMajAx() > 0);
		
		return o1.getMajAx() - o2.getMajAx();
	}
	
}

/**
 * <p>Title: compareMinAx Class</p>
 * Description: CS 235 Assignment 3 
 * 	    Contains the methods to sort by minor axis 
 * @author Jared Potter, Tim Drallmeier, Kyle Kolstad, and Patrick Altendorfer 
 * @date   December 1, 2011
 */
public class compareMinAx implements Comparator<Ellipse>{
	
	/**
	 * Compares two Ellipse objects so they can be used to sort by major axis
	 * 
	 * @require o1.getMinAx() > 0
	 * 			o2.getMinAx() > 0
	 * 
	 * @ensure o1.getMinAx() - o2.getMinAx()  = any valid number
	 */
	
	public int compare(Ellipse o1, Ellipse o2) {
		
		
		assert(o1.getMinAx() > 0);
		assert(o2.getMinAx() > 0);
		
		return o1.getMinAx() - o2.getMinAx();
	}
	
}
}
